﻿using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using JariZ;
using JiveMessenger.CustomEventArgs;
using JiveMessenger.Models;
using JiveMessenger.User;
using JiveMessenger.Utilities;
using JmShared;
using NLog;
using WinampLib;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Input;



namespace JiveMessenger.ViewModels
{
    public class ViewModelPrivateMessage : ViewModelChat
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        private DateTime _lastNudge;
        private IClient _currentClient;
        private IContact _currentUser;
        private string _pmTargetUsername;
        public RelayCommand NudgeCommand { get; set; }
        public RelayCommand NowWritingCommand { get; set; }
        public RelayCommand<WriteMessageEventArgs> SendMessageCommand { get; set; }
        public RelayCommand AddEmoticonCommand { get; private set; }
        public RelayCommand WinampNowPlayingCommand { get; set; }
        public RelayCommand SpotifyNowPlayingCommand { get; set; }
        public RelayCommand<KeyEventArgs> PreviewKeyUpCommand { get; private set; }
        public RelayCommand<AddEditEmoticonEventArgs> EditEmoticonCommand { get; private set; }
        public RelayCommand CollapseChatContactsListCommand { get; private set; }
        public RelayCommand<MessageDownload> LoadMessagesFromServerCommand { get; set; }
        public RelayCommand EditFontCommand { get; set; }

        public IContact PmTarget
        {
            get
            {
                IContact contact = null;
                Messenger.Default.Send(new NotificationMessageAction<IContact>(this,this._pmTargetUsername, "GetContactFromUsername", cont =>
                    {
                        contact = cont;
                    }));
                return contact;
            }
        }

        private ContactListState _contactListState;
        public ContactListState ContactListState
        {
            get { return _contactListState; }
            set
            {
                if (_contactListState != value)
                {
                    Set(() => ContactListState, ref _contactListState, value);
                }
            }
        }

        ~ViewModelPrivateMessage()
        {
            Logger.Debug("ViewModelPrivateMessage destructed");
        }
        public ViewModelPrivateMessage(IClient currentClient, IContact model, IContact currentUser, bool loadLastMessagesFromLog, bool loadLastMessagesAsync)
            : base(currentClient, model.UserName, !String.IsNullOrEmpty(model.NickName) ? model.NickName : model.UserName)
        {
            this._currentClient = currentClient;
            this._currentUser = currentUser;
          //  this.PmTarget = model;
            this._pmTargetUsername = model.UserName;

            if (IsInDesignMode)
            {

            }
            else
            {
#if DEBUG
                Stopwatch sw = Stopwatch.StartNew();
#endif
                ManualResetEvent loadLogWaitEvent = new ManualResetEvent(false);
                ContactListState state = ViewModels.ContactListState.Wide;
                if (ProgramSettings.Instance.ContactListState != null && ProgramSettings.Instance.ContactListState.TryGetValue(this.ID, out state))
                {
                    this.ContactListState = state;
                }

                ShowAsTab = _currentClient.PrivateMessageBehavior != PrivateMessageBehavior.Windows;
                this.ChatLog = new ChatLog(PmTarget.UserName, ProgramSettings.Instance.LogFolder, _currentClient.CurrentUserInfo.UserName);
                this.ChatLog.LogLoaded += (s, args) =>
                {
                    loadLogWaitEvent.Set();
                    if (loadLastMessagesAsync)
                    {
                        int count = ProgramSettings.Instance.LastConversationLogMessageCount;
                        LoadLastChatLogs(count, loadLastMessagesAsync);
                    }
                };

                this.NudgeCommand = new RelayCommand(NudgeCommandAction, () => _currentClient.IsLoggedIn);
                this.SendMessageCommand = new RelayCommand<WriteMessageEventArgs>(SendMessageCommandAction, (e) => _currentClient.IsLoggedIn);
                this.NowWritingCommand = new RelayCommand(NowWritingCommandAction, () => _currentClient.IsLoggedIn);
                this.WinampNowPlayingCommand = new RelayCommand(WinampNowPlayingCommandAction, () => _currentClient.IsLoggedIn);
                this.SpotifyNowPlayingCommand = new RelayCommand(SpotifyNowPlayingCommandAction, () => _currentClient.IsLoggedIn);
                this.AddEmoticonCommand = new RelayCommand(AddEmoticonCommandAction);
                this.EditEmoticonCommand = new RelayCommand<AddEditEmoticonEventArgs>(EditEmoticonCommandAction);
                this.CollapseChatContactsListCommand = new RelayCommand(CollapseChatContactsListCommandAction);
                this.LoadMessagesFromServerCommand = new RelayCommand<MessageDownload>(LoadMessagesFromServerCommandAction, (e) => _currentClient.IsLoggedIn);
                this.EditFontCommand = new RelayCommand(EditFontCommandAction, () => _currentClient.IsLoggedIn);

                this.PropertyChanged += ViewModelPrivateMessage_PropertyChanged;
                //_currentClient.StopReconnectRetrying = false;
                Messenger.Default.Register<NotificationMessage<IContact>>(this, msg =>
                {
                    switch (msg.Notification)
                    {
                        case "UpdatePrivateMessage":
                            IContact contact = msg.Content;
                            if (contact.UserName == this.ID)
                            {
                                this.ViewModelName = contact.PrettyName;
                            }
                            break;
                    }
                });
                if (!loadLastMessagesAsync && loadLastMessagesFromLog)
                {
                    loadLogWaitEvent.WaitOne(2000);
#if DEBUG
                    Logger.Info(string.Format("Time to load log for chat {0} is {1}ms",this.ViewModelName,sw.ElapsedMilliseconds));
#endif
                    int count = ProgramSettings.Instance.LastConversationLogMessageCount;
                    LoadLastChatLogs(count, loadLastMessagesAsync);
                }
            }
        }
        private void LoadMessagesFromServerCommandAction(MessageDownload messageDownload)
        {
            _currentClient.Connection.SendCommand(new MessageRequest(this.ID, messageDownload.Count, messageDownload.AgeInHours), ClientCommands.RequestPrivateMessages);
            IsDownloadMessagePopupOpen = false;

        }
        private void EditFontCommandAction()
        {
            Messenger.Default.Send<NotificationMessage>(new NotificationMessage(this, "ChangeFont"));
        }

        private void LoadLastChatLogs(int count, bool loadAsync)
        {
            int letterCount = 0;
            foreach (LogElement element in ChatLog.ExistingLog.Skip(ChatLog.ExistingLog.Count - count))
            {
                if (letterCount > 500)
                    break;
                Messenger.Default.Send(new NotificationMessageAction<IContact>(this, element.From, "GetContactFromUsername", contact =>
                {
                    if (contact != null)
                    {
                        var senderContact = contact;
                        Application.Current.Dispatcher.Invoke(() =>
                            {
                                DisplayMessage(new DisplayMessage(senderContact, element.Text, this.PmTarget.UserName, DisplayMessageOptions.LastConversationLogOption, element.TimeStamp));
                            });
                        letterCount += element.Text.Length;
                    }
                }));
            }
        }





        private void CollapseChatContactsListCommandAction()
        {
            if (this.ContactListState == ContactListState.Short)
                this.ContactListState = ContactListState.Wide;
            else if (this.ContactListState == ContactListState.Wide)
                this.ContactListState = ContactListState.Short;
        }


        private void SpotifyNowPlayingCommandAction()
        {

            if (_currentClient.SpotifyApi == null)
            {
                this.DisplayMessage(new DisplayMessage(_currentUser, String.Format("Something went wrong. Check that spotify is running and try again in a few seconds."), this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
                _currentClient.InitSpotifyApi();
                return;
            }
            Responses.Status Current_Status = _currentClient.SpotifyApi.Status;
            if (Current_Status.track == null)
            {
                this.DisplayMessage(new DisplayMessage(_currentUser, "You are not listening to any songs", this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
                return;
            }
            string formattedString = string.Format("<s_music>{0}</s_music>", _currentClient.GetSpotifyNowPlayingText());
            ChatMessage msg = new ChatMessage(_currentClient.CurrentUserInfo.ID, _currentClient.CurrentUserInfo.UserName, MessageType.PrivateMessage)
            {
                RecipientID = this.PmTarget.UserName,
                Message = formattedString
            };
            try
            {
                if (!_currentClient.Connection.SendMessage(msg))
                    this.DisplayMessage(new DisplayMessage(_currentUser, String.Format("Could not deliver message: \r\n{0}", msg.Message), this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
                else
                    this.DisplayMessage(new DisplayMessage(_currentUser, msg.Message, this.PmTarget.UserName, DisplayMessageOptions.ChatMessageOption, DateTime.Now));
            }
            catch (OperationCanceledException ex)
            {
                this.DisplayMessage(new DisplayMessage(_currentUser, ex.Message, this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
            }
        }
        private void WinampNowPlayingCommandAction()
        {
            Tuple<string, TrackInfo> result = _currentClient.GetWinampNowPlayingText();
            string formattedString = string.Format("<w_music>{0}</w_music>", result.Item1);
            var trackInfo = result.Item2;

            if (trackInfo.PlaybackStatus.ToString() == "Paused" || trackInfo.PlaybackStatus.ToString() == "Stopped" || trackInfo.PlaybackStatus.ToString() == "Error")
            {
                this.DisplayMessage(new DisplayMessage(_currentUser, String.Format("You are not listening to any songs"), this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
                return;
            }
            ChatMessage msg = new ChatMessage(_currentClient.CurrentUserInfo.ID, _currentClient.CurrentUserInfo.UserName, MessageType.PrivateMessage)
            {
                RecipientID = this.PmTarget.UserName,
                Message = formattedString
            };
            try
            {
                if (!_currentClient.Connection.SendMessage(msg))
                    this.DisplayMessage(new DisplayMessage(_currentUser, String.Format("Could not deliver message: \r\n{0}", msg.Message), this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
                else
                    this.DisplayMessage(new DisplayMessage(_currentUser, msg.Message, this.PmTarget.UserName, DisplayMessageOptions.ChatMessageOption, DateTime.Now));
            }
            catch (OperationCanceledException ex)
            {
                this.DisplayMessage(new DisplayMessage(_currentUser, ex.Message, this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
            }

        }
        private void EditEmoticonCommandAction(AddEditEmoticonEventArgs e)
        {
            Messenger.Default.Send(new NotificationMessage<IEmoticon>(this, e.Emoticon, "EditEmoticon"));
        }
        private void AddEmoticonCommandAction()
        {
            Messenger.Default.Send(new NotificationMessage(this, "AddEmoticon"));
        }
        private void ViewModelPrivateMessage_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "ContactListState":
                    {
                        if (ProgramSettings.Instance.ContactListState == null)
                            ProgramSettings.Instance.ContactListState = new Dictionary<string, ViewModels.ContactListState>();
                        ProgramSettings.Instance.ContactListState[this.ID] = this.ContactListState;
                        Properties.Settings.Default.SettingStoredChatContactListState = StaticMethods.ObjectToString(ProgramSettings.Instance.ContactListState);
                        Properties.Settings.Default.Save();
                    }
                    break;
            }
        }

        public override void Cleanup()
        {
            this.PropertyChanged -= ViewModelPrivateMessage_PropertyChanged;

            base.Cleanup();
        }

        private void SendMessageCommandAction(WriteMessageEventArgs e)
        {
            SendMessage(e.Message);
        }

        private void NowWritingCommandAction()
        {
            _currentClient.Connection.SendMessage(new ChatMessage(_currentClient.CurrentUserInfo.ID, _currentClient.CurrentUserInfo.UserName, MessageType.IsWriting, "PM", this.PmTarget.UserName));
        }
        private void NudgeCommandAction()
        {
            if (DateTime.Now.Subtract(this._lastNudge).TotalSeconds < 5)
            {
                this.DisplayMessage(new DisplayMessage(_currentUser, "You may not send a nudge that often.", this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
                return;
            }

            ChatMessage msg = new ChatMessage(_currentClient.CurrentUserInfo.ID, _currentClient.CurrentUserInfo.UserName, MessageType.Nudge, "PM", this.PmTarget.UserName);

            _currentClient.Connection.SendMessage(msg);
            if (Properties.Settings.Default.SettingEnableSounds && Properties.Settings.Default.SettingEnableNudgeNotificationSound)
                _currentClient.PlayNudgeSound();
            Messenger.Default.Send(new NotificationMessage(this, "Nudge"));
            this.DisplayMessage(new DisplayMessage(_currentUser, "You have sent a nudge!", this.PmTarget.UserName, DisplayMessageOptions.NudgeOptions, DateTime.Now));
            this._lastNudge = DateTime.Now;
        }


        private void SendMessage(string text)
        {
            ChatMessage msg = new ChatMessage(_currentClient.CurrentUserInfo.ID, _currentClient.CurrentUserInfo.UserName, MessageType.PrivateMessage, text, this.PmTarget.UserName)
            {
                MessageID = _currentClient.MessageID++
            };
            this.DisplayMessage(new DisplayMessage(_currentUser, text, this.PmTarget.UserName, DisplayMessageOptions.ChatMessageOption, DateTime.Now));
            try
            {
                if (!_currentClient.Connection.SendMessage(msg))
                {
                    if (msg.MessageType == MessageType.PrivateMessage)
                        DisplayMessage(new DisplayMessage(_currentUser, String.Format("Message response timeout. It is possible the message was not received: {0}", msg.Message), this.PmTarget.UserName,DisplayMessageOptions.ErrorOptions, DateTime.Now));
                }
            }
            catch (OperationCanceledException ex)
            {
               // this.DisplayMessage(_currentUser, ex.Message, DisplayMessageOptions.ErrorOptions, DateTime.Now);
                DisplayMessage(new DisplayMessage(_currentUser, ex.Message, this.PmTarget.UserName, DisplayMessageOptions.ErrorOptions, DateTime.Now));
            }
        }

        public override void DisplayMessage(DisplayMessage displayMessage)
        {
            displayMessage.ChatTarget = this.PmTarget.UserName;
            base.DisplayMessage(displayMessage);
        }

        //public override void DisplayMessage(IContact sender, string message, DisplayMessageOptions options, DateTime timestamp)
        //{
        //    DisplayMessage(new DisplayMessage(sender, message, this.PmTarget.UserName, options, timestamp));
        //    if (!IsInDesignMode)
        //    {
        //        if (options.BlinkTab && !this.IsCurrentActiveTab)
        //            this.IsBlinking = true;
        //    }
        //}



    }
}
